/*
 *
 */
#include "gkt_debug.h"
#include "gkt_gpio.h"
#include "gkt_os.h"
#include "gkt_ambient_light.h"

#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN)
#ifdef GKT_CONFIG_AMBIENT_LIGHT_STATE_2_LEVEL
#define AMBIENT_LIGHT_STATE_META_2_LEVEL	\
	GKT_CONFIG_AMBIENT_LIGHT_STATE_2_LEVEL
#else
#define AMBIENT_LIGHT_STATE_META_2_LEVEL	1
#endif

#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_ON)	\
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_2_ON == 0)
#define AMBIENT_LIGHT_META_2_OUTPUT			GKT_GPIO_F_OUTPUT|GKT_GPIO_F_OUTPUT_HIGH		
#define AMBIENT_LIGHT_META_2_OFF			1
#else
#define AMBIENT_LIGHT_META_2_OUTPUT			GKT_GPIO_F_OUTPUT
#define AMBIENT_LIGHT_META_2_OFF			0
#endif
#define AMBIENT_LIGHT_META_2_ON				GKT_CONFIG_AMBIENT_LIGHT_META_2_ON
#endif

#if GKT_AMBIENT_LIGHT_ENABLE \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_COLOR_NUMS) \
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_COLOR_NUMS == 3) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_GPIO_PIN_NUMS) \
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_GPIO_PIN_NUMS == 3) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN)	
#ifdef GKT_CONFIG_AMBIENT_LIGHT_STATE_0_LEVEL
#define AMBIENT_LIGHT_STATE_META_0_LEVEL	\
	GKT_CONFIG_AMBIENT_LIGHT_STATE_0_LEVEL
#else
#define AMBIENT_LIGHT_STATE_META_0_LEVEL	1
#endif

#ifdef GKT_CONFIG_AMBIENT_LIGHT_STATE_1_LEVEL
#define AMBIENT_LIGHT_STATE_META_1_LEVEL	\
	GKT_CONFIG_AMBIENT_LIGHT_STATE_1_LEVEL
#else
#define AMBIENT_LIGHT_STATE_META_1_LEVEL	1
#endif

#if defined(GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE) \
	&& GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE
#define AMBIENT_LIGHT_FLICKER_ENABLE	1
#else
#define AMBIENT_LIGHT_FLICKER_ENABLE	0
#endif

#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_0_ON)	\
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_0_ON == 0)
#define AMBIENT_LIGHT_META_0_OUTPUT			GKT_GPIO_F_OUTPUT|GKT_GPIO_F_OUTPUT_HIGH	
#define AMBIENT_LIGHT_META_0_OFF			1
#else
#define AMBIENT_LIGHT_META_0_OUTPUT			GKT_GPIO_F_OUTPUT
#define AMBIENT_LIGHT_META_0_OFF			0
#endif
#define AMBIENT_LIGHT_META_0_ON				GKT_CONFIG_AMBIENT_LIGHT_META_0_ON	
	
#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_1_ON)	\
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_1_ON == 0)
#define AMBIENT_LIGHT_META_1_OUTPUT			GKT_GPIO_F_OUTPUT|GKT_GPIO_F_OUTPUT_HIGH		
#define AMBIENT_LIGHT_META_1_OFF			1
#else
#define AMBIENT_LIGHT_META_1_OUTPUT			GKT_GPIO_F_OUTPUT
#define AMBIENT_LIGHT_META_1_OFF			0
#endif
#define AMBIENT_LIGHT_META_1_ON				GKT_CONFIG_AMBIENT_LIGHT_META_1_ON

enum {
	AMBIENT_LIGHT_STATE_OFF = GKT_AMBIENT_LIGHT_STATE_OFF,
	AMBIENT_LIGHT_STATE_META_0,	/* meta state 0 */
	AMBIENT_LIGHT_STATE_META_1,	/* meta state 1 */
	AMBIENT_LIGHT_STATE_META_2,	/* meta state 2 */
	AMBIENT_LIGHT_STATE_MIXED,	/* mixed state - meta state 0 & 1 & 2*/
	AMBIENT_LIGHT_STATE_MAX
};

static const uint32_t sc_ambient_light_state_meta_level_bits = 
	((AMBIENT_LIGHT_STATE_META_0_LEVEL << 0) | (AMBIENT_LIGHT_STATE_META_1_LEVEL << 1) | (AMBIENT_LIGHT_STATE_META_2_LEVEL << 2));

typedef struct _ambient_light {
#if AMBIENT_LIGHT_FLICKER_ENABLE
	gkt_mutex_t	mutex;
	gkt_soft_timer_t	flicker_soft_timer;
	int	flicker_soft_timer_start;
	uint32_t	flicker_loops_left;
	int	flicker_light_on;
#endif

	uint32_t	state;
} ambient_light_s;
static ambient_light_s s_ambient_light;

static void ambient_light_off(int complete)
{
	uint32_t levels[3];

	if (complete) {
		s_ambient_light.state = GKT_AMBIENT_LIGHT_STATE_OFF;
#if AMBIENT_LIGHT_FLICKER_ENABLE
		s_ambient_light.flicker_loops_left = 0;
		if (s_ambient_light.flicker_soft_timer_start) {
			s_ambient_light.flicker_soft_timer_start = 0;
			gkt_soft_timer_stop(s_ambient_light.flicker_soft_timer);
		}
#endif
	}

	levels[0] = (sc_ambient_light_state_meta_level_bits & 0x01) ? AMBIENT_LIGHT_META_0_OFF : AMBIENT_LIGHT_META_0_ON;
	levels[1] = (sc_ambient_light_state_meta_level_bits & 0x02) ? AMBIENT_LIGHT_META_1_OFF : AMBIENT_LIGHT_META_1_ON;
	levels[2] = (sc_ambient_light_state_meta_level_bits & 0x04) ? AMBIENT_LIGHT_META_2_OFF : AMBIENT_LIGHT_META_2_ON;
	
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN, levels[0]);
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN, levels[1]);
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN, levels[2]);
}

static void ambient_light_on(uint32_t state)
{
	uint32_t levels[3];

	if (AMBIENT_LIGHT_STATE_META_0 == state) {
		levels[0] = (sc_ambient_light_state_meta_level_bits & 0x01) ? AMBIENT_LIGHT_META_0_ON : AMBIENT_LIGHT_META_0_OFF;
		levels[1] = (sc_ambient_light_state_meta_level_bits & 0x02) ? AMBIENT_LIGHT_META_1_OFF : AMBIENT_LIGHT_META_1_ON;
		levels[2] = (sc_ambient_light_state_meta_level_bits & 0x04) ? AMBIENT_LIGHT_META_2_OFF : AMBIENT_LIGHT_META_2_ON;
	}
	else if (AMBIENT_LIGHT_STATE_META_1 == state) {
		levels[0] = (sc_ambient_light_state_meta_level_bits & 0x01) ? AMBIENT_LIGHT_META_0_OFF : AMBIENT_LIGHT_META_0_ON;
		levels[1] = (sc_ambient_light_state_meta_level_bits & 0x02) ? AMBIENT_LIGHT_META_1_ON : AMBIENT_LIGHT_META_1_OFF;
		levels[2] = (sc_ambient_light_state_meta_level_bits & 0x04) ? AMBIENT_LIGHT_META_2_OFF : AMBIENT_LIGHT_META_2_ON;
	}
	else if (AMBIENT_LIGHT_STATE_META_2 == state) {
		levels[0] = (sc_ambient_light_state_meta_level_bits & 0x01) ? AMBIENT_LIGHT_META_0_OFF : AMBIENT_LIGHT_META_0_ON;
		levels[1] = (sc_ambient_light_state_meta_level_bits & 0x02) ? AMBIENT_LIGHT_META_1_OFF : AMBIENT_LIGHT_META_1_ON;
		levels[2] = (sc_ambient_light_state_meta_level_bits & 0x04) ? AMBIENT_LIGHT_META_2_ON : AMBIENT_LIGHT_META_2_OFF;
	}
	else {
		levels[0] = (sc_ambient_light_state_meta_level_bits & 0x01) ? AMBIENT_LIGHT_META_0_ON : AMBIENT_LIGHT_META_0_OFF;
		levels[1] = (sc_ambient_light_state_meta_level_bits & 0x02) ? AMBIENT_LIGHT_META_1_ON : AMBIENT_LIGHT_META_1_OFF;
		levels[2] = (sc_ambient_light_state_meta_level_bits & 0x04) ? AMBIENT_LIGHT_META_2_ON : AMBIENT_LIGHT_META_2_OFF;
	}	
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN, levels[0]);
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN, levels[1]);
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN, levels[2]);
}

#if AMBIENT_LIGHT_FLICKER_ENABLE
static void ambient_light_flicker_timer_callback(void *arguments)
{
	gkt_mutex_lock(s_ambient_light.mutex, GKT_INFINITE);
	if (s_ambient_light.flicker_soft_timer_start) {
		if (s_ambient_light.flicker_loops_left > 0) {
			if (s_ambient_light.flicker_light_on) {
				s_ambient_light.flicker_light_on = 0;
				ambient_light_off(0);
			}
			else {
				s_ambient_light.flicker_loops_left--;
				s_ambient_light.flicker_light_on = 1;
				ambient_light_on(s_ambient_light.state);
			}
		}
		else
			ambient_light_off(1);
	}
	gkt_mutex_unlock(s_ambient_light.mutex);
}

void gkt_ambient_light_set_state(uint32_t state, 
		uint32_t half_cycle_time_ms, uint32_t loops)
{
	int retval;

	if (s_ambient_light.mutex)
		gkt_mutex_lock(s_ambient_light.mutex, GKT_INFINITE);

	if ((AMBIENT_LIGHT_STATE_OFF == state)
		&& (s_ambient_light.state != state))
	{
		ambient_light_off(1);
	}
	else if (state < AMBIENT_LIGHT_STATE_MAX) {
		if (s_ambient_light.flicker_soft_timer_start) {
			s_ambient_light.flicker_soft_timer_start = 0;
			gkt_soft_timer_stop(s_ambient_light.flicker_soft_timer);
		}

		if (s_ambient_light.state != state) {
			ambient_light_on(state);
			s_ambient_light.state = state;
		}

		if ((half_cycle_time_ms > 0) && (loops > 0)
			&& s_ambient_light.flicker_soft_timer) 
		{
			s_ambient_light.flicker_light_on = 1;
			s_ambient_light.flicker_loops_left = loops - 1;
			retval = gkt_soft_timer_start(s_ambient_light.flicker_soft_timer,
							half_cycle_time_ms);
			if (GKT_SUCCESS == retval)
				s_ambient_light.flicker_soft_timer_start = 1;
		}
	}

	if (s_ambient_light.mutex)
		gkt_mutex_unlock(s_ambient_light.mutex);
}

#else
void gkt_ambient_light_set_state(uint32_t state, 
		uint32_t half_cycle_time_ms, uint32_t loops)
{
	gkt_unused(half_cycle_time_ms);
	gkt_unused(loops);

	if (s_ambient_light.state != state) {
		if (AMBIENT_LIGHT_STATE_OFF == state)
			ambient_light_off(1);
		else if (state < AMBIENT_LIGHT_STATE_MAX) {
			ambient_light_on(state);
			s_ambient_light.state = state;
		}
	}
}
#endif
#endif

#if (GKT_AMBIENT_LIGHT_ENABLE \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_COLOR_NUMS) \
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_COLOR_NUMS == 3) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_GPIO_PIN_NUMS) \
	&& (GKT_CONFIG_AMBIENT_LIGHT_META_GPIO_PIN_NUMS == 3) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN) \
	&& defined(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN))	\
	|| defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN)	
void gkt_ambient_light_init(void)
{
	int retval;

#if (GKT_AMBIENT_LIGHT_ENABLE) && defined(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN)
	retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN,
					AMBIENT_LIGHT_META_0_OUTPUT, NULL);
	if (retval != GKT_SUCCESS)
		gkt_error("ambient_light: config meta_0 gpio failed(%d)!\n", retval);
#endif
#if (GKT_AMBIENT_LIGHT_ENABLE) && defined(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN)
	retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN,
					AMBIENT_LIGHT_META_1_OUTPUT, NULL);
	if (retval != GKT_SUCCESS)
		gkt_error("ambient_light: config meta_1 gpio failed(%d)!\n", retval);
#endif
#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN)
	retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN,
					AMBIENT_LIGHT_META_2_OUTPUT, NULL);
	if (retval != GKT_SUCCESS)
		gkt_error("ambient_light: config meta_2 gpio failed(%d)!\n", retval);
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN, GKT_CONFIG_AMBIENT_LIGHT_META_2_ON);
#endif

#if GKT_AMBIENT_LIGHT_ENABLE && defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN)
	ambient_light_off(1);
#endif

#if GKT_AMBIENT_LIGHT_ENABLE && AMBIENT_LIGHT_FLICKER_ENABLE
	s_ambient_light.flicker_soft_timer_start = 0;

	s_ambient_light.mutex = gkt_mutex_create(0);
	if (!s_ambient_light.mutex)
		gkt_error("ambient_light: create mutex failed!\n");

	s_ambient_light.flicker_soft_timer = gkt_soft_timer_create(
			GKT_SOFT_TIMER_PERIODIC,
			ambient_light_flicker_timer_callback, NULL);
	if (!s_ambient_light.flicker_soft_timer)
		gkt_error("ambient_light: create flicker_soft_timer failed!\n");
#endif
}

int gkt_ambient_light_standby(void)
{
	int retval=GKT_SUCCESS;

#if (GKT_AMBIENT_LIGHT_ENABLE) && defined(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN)
	//gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN, !GKT_CONFIG_AMBIENT_LIGHT_META_0_ON);
	retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_0_GPIO_PIN,
					GKT_GPIO_F_INPUT|GKT_GPIO_F_INPUT_PULL_DOWN, NULL);
	if (retval != GKT_SUCCESS)
		gkt_error("ambient_light: config meta_0 gpio failed(%d)!\n", retval);
#endif
#if (GKT_AMBIENT_LIGHT_ENABLE) && defined(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN)
	//gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN, !GKT_CONFIG_AMBIENT_LIGHT_META_1_ON);
	retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_1_GPIO_PIN,
					GKT_GPIO_F_INPUT|GKT_GPIO_F_INPUT_PULL_DOWN, NULL);
	if (retval != GKT_SUCCESS)
		gkt_error("ambient_light: config meta_1 gpio failed(%d)!\n", retval);
#endif

#if defined(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN)
	gkt_gpio_set_pin_level(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN, !GKT_CONFIG_AMBIENT_LIGHT_META_2_ON);
	//retval = gkt_gpio_config(GKT_CONFIG_AMBIENT_LIGHT_META_2_GPIO_PIN,
	//				GKT_GPIO_F_INPUT|GKT_GPIO_F_INPUT_PULL_DOWN, NULL);
	//if (retval != GKT_SUCCESS)
		//gkt_error("ambient_light: config meta_2 gpio failed(%d)!\n", retval);
#endif
	return retval;
}
#endif
